import {
  Controller,
  Inject,
  Get,
  Post,
  Body,
  Files,
  Param,
} from '@midwayjs/decorator';
import {
  LoginType,
  RegisterType,
  ChangePassType,
} from '../interface/user.interface';
import { Context } from '@midwayjs/koa';
import { UserService } from '../service/user.service';
import { UploadService } from '../service/upload.service';

import {
  UserNotFound,
  Unauthorized,
  PasswordDiffer,
} from '../error/custom.error';
import { JwtService } from '@midwayjs/jwt';
import {
  checkEssentialParams,
  md5,
  getUserFromToken,
  isBetween,
} from '../utils';
import { UploadType } from '../interface/upload.interface';
import { JwtPassportMiddleware } from '../middleware/jwt.middleware';
import { AntiBurstMiddleware } from '../middleware/antiburst.middleware';

@Controller()
export class UserController {
  @Inject()
  ctx: Context;

  @Inject()
  userService: UserService;

  @Inject()
  jwt: JwtService;

  @Inject()
  uploadService: UploadService;

  // 认证接口 (登录状态维持)
  @Post('/auth', { middleware: [JwtPassportMiddleware] })
  async auth() {
    const payload = this.jwt.decode(
      this.ctx.get('Authorization').split(' ')[1]
    ) as object;
    return {
      msg: 'success',
      ...payload,
    };
  }

  // 登录接口
  @Post('/login', { middleware: [AntiBurstMiddleware] })
  async login(@Body() { username, password }: LoginType) {
    checkEssentialParams(username, password);
    const target = await this.userService.findUser(
      username,
      t => {
        this.userService.changeUser(t, { updateTime: new Date() }); // 刷新用户状态
      },
      () => {
        throw new UserNotFound();
      }
    );
    if (
      md5(password) !== target.password ||
      !isBetween(username.length, [4, 18], true) ||
      !isBetween(password.length, [4, 18], true)
    ) {
      return { error: 'Unauthorized' };
    }
    return {
      token: await this.userService.generateToken(username),
      username: target.username,
      avatar: target.avatar,
      background: target.background,
    };
  }

  // 注册接口
  @Post('/register')
  async register(
    @Body() { username, password, confirmPassword }: RegisterType
  ) {
    checkEssentialParams(username, password, confirmPassword);
    await this.userService.addUser(username, password, confirmPassword);
    return { username };
  }

  // 修改密码(常规做法)
  @Post('/changePassword', { middleware: [JwtPassportMiddleware] })
  async changePassword(
    @Body() { oldPassword, newPassword, confirmPassword }: ChangePassType
  ) {
    checkEssentialParams(oldPassword, newPassword, confirmPassword);
    if (newPassword !== confirmPassword) {
      throw new PasswordDiffer();
    }
    const target = await getUserFromToken(this.ctx, this.jwt, this.userService);
    if (md5(oldPassword) !== target.password) {
      throw new Unauthorized();
    }
    this.userService.changeUser(target, { password: md5(newPassword) });
    return {
      msg: 'Password updated successfully!',
    };
  }

  // 获取头像 | 背景图
  @Get('/avatar/:filename')
  @Get('/background/:filename')
  async fetchAvatarBackground(@Param('filename') filename: string) {
    const fetchType = this.ctx.url.split('/')[1] as UploadType;
    return this.uploadService.getResource(fetchType, filename);
  }

  // 上传头像 | 背景图
  @Post('/avatar', { middleware: [JwtPassportMiddleware] })
  @Post('/background', { middleware: [JwtPassportMiddleware] })
  async uploadAvatarBackground(@Files() files: any) {
    const uploadTo = this.ctx.url.split('/')[1] as UploadType;
    files.size = parseInt(this.ctx.get('Content-Length')); // 单位：B
    const { url, filename } = await this.uploadService.uploadFile(
      uploadTo,
      files,
      ['jpg', 'jpeg', 'png'],
      ['image/jpeg', 'image/png']
    );
    const target = await getUserFromToken(this.ctx, this.jwt, this.userService);
    // 判断上传的是头像还是背景图
    if (uploadTo === 'avatar') {
      await this.userService.changeUser(target, { avatar: url });
    } else {
      await this.userService.changeUser(target, { background: url });
    }
    return { url, filename };
  }
}
